package user

import (
	"github.com/xinliangnote/go-gin-api/internal/code"
	"github.com/xinliangnote/go-gin-api/internal/pkg/core"
	"github.com/xinliangnote/go-gin-api/internal/pkg/validation"
	userModel "github.com/xinliangnote/go-gin-api/internal/repository/mongodb/user"
	userService "github.com/xinliangnote/go-gin-api/internal/services/user"
	"github.com/xinliangnote/go-gin-api/internal/tools"
	"net/http"
)

type createRequest struct {
	UserName string `bson:"userName" json:"userName"`
	Password string `bson:"password" json:"password"`
	Code     string `bson:"code" json:"code"`
}

type createResponse struct {
	Code int         `json:"code"`
	Data interface{} `json:"data"`
	Msg  string      `json:"msg"`
}

type ResultData struct {
	Token    string `bson:"token" json:"token"`
	UserId   string `bson:"userId" json:"userId"`
	UserName string `bson:"userName" json:"userName"`
	ApiKey   string `bson:"apiKey" json:"apiKey"`
	Email    string `bson:"email" json:"email"`
}

type PasswordData struct {
	UserId      string `bson:"userId" json:"userId"`
	OldPassword string `bson:"OldPassword" json:"OldPassword"`
	NewPassword string `bson:"newPassword" json:"newPassword"`
}

func (h *handler) Login() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(createRequest)
		res := new(createResponse)
		if err := ctx.ShouldBindJSON(req); err != nil {
			ctx.AbortWithError(core.Error(
				http.StatusOK,
				code.ParamBindError,
				validation.Error(err)).WithError(err),
			)
			return
		}

		createData := new(userService.LoginData)
		createData.Password = req.Password
		createData.UserName = req.UserName

		userInfo, err := h.userService.Login(ctx, createData)
		if err != nil {
			ctx.AbortWithError(core.Error(
				http.StatusOK,
				code.LoginError,
				code.Text(code.LoginError)).WithError(err),
			)
			return
		}

		if userInfo.LastLoginIP != ctx.GetClientIP() {

			if req.Code == "" {
				res.Code = code.LoginIPError
				res.Data = userInfo.Email
				res.Msg = code.Text(code.StatusOK)
				ctx.Payload(res)
				return
			} else {
				redisCode, _ := h.cache.Get(userInfo.Email + "_email_code")
				if req.Code != redisCode {
					ctx.AbortWithError(core.Error(
						http.StatusOK,
						code.EmailCodeError,
						code.Text(code.EmailCodeError)).WithError(err),
					)
					return
				}

				h.userService.UpdateLoginIp(ctx, userInfo.Id)
			}
		}

		token, err := tools.GenerateToken(userInfo.ApiKey)
		if err != nil {
			ctx.AbortWithError(core.Error(
				http.StatusOK,
				code.CreateTokenError,
				code.Text(code.CreateTokenError)).WithError(err),
			)
			return
		}

		rd := new(ResultData)
		rd.UserId = userInfo.Id
		rd.UserName = userInfo.Username
		rd.ApiKey = userInfo.ApiKey
		rd.Token = token
		rd.Email = userInfo.Email
		res.Code = code.StatusOK
		res.Data = rd
		res.Msg = code.Text(code.StatusOK)
		ctx.Payload(res)
	}
}

func (h *handler) ChangePassword() core.HandlerFunc {
	return func(ctx core.Context) {
		req := new(PasswordData)
		res := new(createResponse)
		if err := ctx.ShouldBindJSON(req); err != nil {
			ctx.AbortWithError(core.Error(
				http.StatusOK,
				code.ParamBindError,
				validation.Error(err)).WithError(err),
			)
			return
		}

		userInfo := ctx.GetInfo("userInfo").(*userModel.User)
		createData := new(userService.PasswordData)
		createData.UserId = userInfo.Id
		createData.OldPassword = req.OldPassword
		createData.NewPassword = req.NewPassword

		err := h.userService.ChangePassword(ctx, createData)
		if err != nil {
			ctx.AbortWithError(core.Error(
				http.StatusOK,
				code.ChangePasswordError,
				code.Text(code.ChangePasswordError)).WithError(err),
			)
			return
		}

		res.Code = code.StatusOK
		res.Data = nil
		res.Msg = code.Text(code.StatusOK)
		ctx.Payload(res)
	}
}
